home *** CD-ROM | disk | FTP | other *** search
- /*
- * contour.c
- *
- * Practical Algorithms for Image Analysis
- *
- * Copyright (c) 1997, 1998, 1999 MLMSoftwareGroup, LLC
- */
-
- /* CONTOUR: program determines contour boundaries for binary image
- * usage: contour infile.img outfile.img
- *
- */
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include "tiffimage.h" /* picfile info on images */
- #include "images.h"
- extern void print_sos_lic ();
-
- #define ON 0 /* binarization values */
- #define OFF 255
- #define ONM1 1
- #define CONTOUR 32 /* value of contour pixel */
- #define CENTROID 31 /* value of centroid location pixel */
- #define MAX_CONTOUR 10000 /* maximum length of contour */
- #define DISPLAY_FLAG_DFLT 0 /* =0 contours; =1 centroids; =2 both */
-
- #define SQUARE(IMG,X,Y) IMG[Y][X] = ONM1, IMG[Y-1][X-1] = ONM1,\
- IMG[Y-1][X] = ONM1, IMG[Y-1][X+1] = ONM1,\
- IMG[Y][X+1] = ONM1, IMG[Y+1][X+1] = ONM1,\
- IMG[Y+1][X] = ONM1, IMG[Y+1][X-1] = ONM1,\
- IMG[Y][X-1] = ONM1
-
- int nextcntr (unsigned char **, long *, long *, long *);
- long usage (short);
- long input (int, char **, long *, short *, short *);
-
- main (argc, argv)
- int argc;
- char *argv[];
- {
- Image *imgIO; /* I/O image structure */
- unsigned char **image; /* input/output image */
- long height, width; /* size of I/O images */
- long xEndM1, yEndM1; /* end of rows/columns minus one */
- struct cntr { /* structure for each contour pt */
- long x, y; /* location */
- long iDirn; /* chain code direction */
- long curve; /* local curvature */
- } *cntr;
- long maxContour; /* max. contour length (for memory alloc.) */
- short displayFlag; /* =0 contours; =1 centroids; =2 both */
- short printFlag; /* =1 print contour info; =0 don't */
- long nContour; /* number of contours */
- long lContour; /* length of contour */
- long maxLContour; /* max. length of contour */
- long lContourSum; /* sum of contour lengths */
- double xCentroid, yCentroid; /* x,y centroid location for contour */
- long xStart, yStart; /* starting pixels of contour */
- long iDirn; /* direction coming into contour */
- long x, y;
- long temp;
-
- /* user input */
- if (input (argc, argv, &maxContour, &displayFlag, &printFlag) < 0)
- return (-1);
-
- imgIO = ImageIn (argv[1]);
- image = imgIO->img;
- height = ImageGetHeight (imgIO);
- width = ImageGetWidth (imgIO);
- printf ("image size is %dx%d\n", width, height);
-
- /* allocate contour memory */
- if ((cntr = (struct cntr *) calloc (maxContour, sizeof (struct cntr)))
- == NULL) {
- printf ("CONTOUR: not enough memory -- sorry.\n");
- return (-1);
- }
-
- /* determine contours */
- yEndM1 = height - 1;
- xEndM1 = width - 1;
- nContour = 0;
- maxLContour = 0;
- lContourSum = 0;
- for (y = 1; y < yEndM1; y++) {
- for (x = 1; x < xEndM1; x++) {
- /* when find ON-pixel, trace contour */
- if (image[y][x] == ON && image[y][x - 1] == OFF) {
- nContour++;
- iDirn = 2;
- cntr[0].x = xStart = x;
- cntr[0].y = yStart = y;
- xCentroid = (double) x;
- yCentroid = (double) y;
- cntr[0].iDirn = iDirn;
- cntr[0].curve = 0;
- lContour = 1;
- do {
- image[y][x] = CONTOUR;
- nextcntr (image, &x, &y, &iDirn);
- cntr[lContour].x = x;
- cntr[lContour].y = y;
- cntr[lContour].iDirn = iDirn;
- xCentroid += (double) x;
- yCentroid += (double) y;
- temp = iDirn - cntr[lContour - 1].iDirn;
- if (temp > 4)
- temp -= 8;
- else if (temp < -4)
- temp += 8;
- cntr[lContour].curve = temp;
- lContour++;
- if (lContour == MAX_CONTOUR) {
- printf ("Nuts -- maximum contour length reached = %d\n", lContour);
- return (-1);
- }
- } while (!(x == xStart && y == yStart));
- if (lContour > maxLContour)
- maxLContour = lContour;
- xCentroid = xCentroid / (double) lContour;
- yCentroid = yCentroid / (double) lContour;
- lContourSum += lContour;
- if (displayFlag > 0)
- image[(long) (yCentroid + 0.5)][(long) (xCentroid + 0.5)] = CENTROID;
- if (printFlag != 0)
- printf ("contour %ld: length = %ld, centroid = (%5.2f,%5.2f)\n",
- nContour - 1, lContour, xCentroid, yCentroid);
- }
- }
- }
-
- switch (displayFlag) {
- case 0:
- for (y = 0; y < height; y++)
- for (x = 0; x < width; x++)
- image[y][x] = (image[y][x] == CONTOUR) ? ON : OFF;
- break;
- case 1:
- for (y = 0; y < height; y++)
- for (x = 0; x < width; x++) {
- if (image[y][x] == CENTROID)
- SQUARE (image, x, y);
- else if (image[y][x] == ONM1);
- else
- image[y][x] = OFF;
- }
- break;
- case 2:
- for (y = 0; y < height; y++)
- for (x = 0; x < width; x++) {
- if (image[y][x] == CENTROID)
- SQUARE (image, x, y);
- else if (image[y][x] == CONTOUR)
- image[y][x] = ON;
- else if (image[y][x] == ONM1);
- else
- image[y][x] = OFF;
- }
- break;
- default:
- for (y = 0; y < height; y++)
- for (x = 0; x < width; x++)
- image[y][x] = (image[y][x] == CONTOUR) ? ONM1 : OFF;
- }
-
- if (nContour == 0)
- printf ("no image regions\n");
- else
- printf ("no. contours = %d, max length = %d, avg. length = %d\n",
- nContour, maxLContour, lContourSum / nContour);
-
- ImageOut (argv[2], imgIO);
-
- return (0);
- }
-
-
-
- /* NEXTCNTR: function examines neighborhood for next contour pixel
- */
-
- int
- nextcntr (image, x, y, iDirn)
- unsigned char **image;
- long *x, *y; /* temporary x and y storage for trace */
- long *iDirn; /* direction from last pixel on contour */
- {
- long ring[16]; /* neighborhood ring of pixels */
- long i, j;
-
- /* find neighborhood ring of pixels */
- ring[0] = ring[8] = image[*y - 1][*x];
- ring[1] = ring[9] = image[*y - 1][*x + 1];
- ring[2] = ring[10] = image[*y][*x + 1];
- ring[3] = ring[11] = image[*y + 1][*x + 1];
- ring[4] = ring[12] = image[*y + 1][*x];
- ring[5] = ring[13] = image[*y + 1][*x - 1];
- ring[6] = ring[14] = image[*y][*x - 1];
- ring[7] = ring[15] = image[*y - 1][*x - 1];
-
- i = (*iDirn + 4 + 1) % 8;
-
- for (j = 0; j < 8; j++, i++)
- if (ring[i] != OFF && ring[i - 1] == OFF)
- break;
-
- if (j == 8)
- return (0); /* isolated pixel */
-
- *iDirn = i % 8;
-
- switch (i) {
- case 1:
- case 9:
- *x = *x + 1;
- *y = *y - 1;
- break;
- case 2:
- case 10:
- *x = *x + 1;
- break;
- case 3:
- case 11:
- *x = *x + 1;
- *y = *y + 1;
- break;
- case 4:
- case 12:
- *y = *y + 1;
- break;
- case 5:
- case 13:
- *x = *x - 1;
- *y = *y + 1;
- break;
- case 6:
- case 14:
- *x = *x - 1;
- break;
- case 7:
- case 15:
- *x = *x - 1;
- *y = *y - 1;
- break;
- case 8:
- case 0:
- *y = *y - 1;
- break;
- default:;
- }
-
- return (0);
- }
-
-
-
-
- /* USAGE: function gives instructions on usage of program
- * usage: usage (flag)
- * When flag is 1, the long message is given, 0 gives short.
- */
-
- long
- usage (flag)
- short flag; /* flag =1 for long message; =0 for short message */
- {
-
- /* print short usage message or long */
- printf ("USAGE: contour inimg outimg [-d DISPLAY] [-p] \n");
- printf (" [-m MAX_CONTOUR_LENGTH] [-L]\n");
- if (flag == 0)
- return (-1);
-
- printf ("\ncontour identifies contours, or boundaries, of regions\n");
- printf ("in a binary image, and determines features of the regions.\n\n");
- printf ("ARGUMENTS:\n");
- printf (" inimg: input image filename (TIF)\n");
- printf (" outimg: output image filename (TIF)\n\n");
- printf ("OPTIONS:\n");
- printf (" -d DISPLAY: display just centroids (1), or both\n");
- printf (" contours and centroids (2);\n");
- printf (" default displays just contours.\n");
- printf (" -p: PRINT DATA FLAG if set, prints contour\n");
- printf (" number, length, and centroid data.\n");
- printf (" -m MAX_CONTOUR_LENGTH: maximum contour length in pixel\n");
- printf (" connections. (Default = %d)\n", MAX_CONTOUR);
- printf (" -L: print Software License for this module\n");
-
- return (-1);
- }
-
-
- /* INPUT: function reads input parameters
- * usage: input (argc, argv, &maxContour, &displayFlag)
- */
-
- #define USAGE_EXIT(VALUE) {usage (VALUE); return (-1);}
-
- long
- input (argc, argv, maxContour, displayFlag, printFlag)
- int argc;
- char *argv[];
- long *maxContour; /* maximum contour length (for memory alloc) */
- short *displayFlag; /* =0 contours; =1 centroids; =2 both */
- short *printFlag; /* =1, print contour data; =0 don't */
- {
- long n;
-
- if (argc == 1)
- USAGE_EXIT (1);
- if (argc == 2)
- USAGE_EXIT (0);
-
- *maxContour = MAX_CONTOUR;
- *displayFlag = DISPLAY_FLAG_DFLT;
- *printFlag = 0;
-
- for (n = 3; n < argc; n++) {
- if (strcmp (argv[n], "-m") == 0) {
- if (++n == argc || argv[n][0] == '-')
- USAGE_EXIT (0);
- *maxContour = atol (argv[n]);
- }
- else if (strcmp (argv[n], "-d") == 0) {
- if (++n == argc || argv[n][0] == '-')
- USAGE_EXIT (0);
- *displayFlag = (short) atol (argv[n]);
- }
- else if (strcmp (argv[n], "-p") == 0) {
- *printFlag = 1;
- }
- else if (strcmp (argv[n], "-L") == 0) {
- print_sos_lic ();
- exit (0);
- }
- else
- USAGE_EXIT (0);
- }
-
- return (0);
- }
-